package org.test.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
import org.test.granter.password.OAuth2PasswordAuthenticationConverter;
import org.test.granter.password.OAuth2PasswordAuthenticationProvider;

@Configuration
@EnableWebSecurity
public class SecurityConfig {


    private final OAuth2PasswordAuthenticationProvider oAuth2PasswordAuthenticationProvider;
    private final OAuth2PasswordAuthenticationConverter oAuth2PasswordAuthenticationConverter;

    public SecurityConfig(OAuth2PasswordAuthenticationProvider oAuth2PasswordAuthenticationProvider, OAuth2PasswordAuthenticationConverter oAuth2PasswordAuthenticationConverter) {
        this.oAuth2PasswordAuthenticationProvider = oAuth2PasswordAuthenticationProvider;
        this.oAuth2PasswordAuthenticationConverter = oAuth2PasswordAuthenticationConverter;
    }

    /**
     * Spring Authorization Server 相关配置
     * 主要配置OAuth 2.1和OpenID Connect 1.0
     *
     * @param http
     * @return
     * @throws Exception
     */
    @Bean
    @Order(1)
    public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
        OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = OAuth2AuthorizationServerConfigurer.authorizationServer();

        // 注册自定义的 Token Response Converter 有问题，使用默认的
        //authorizationServerConfigurer.tokenEndpoint(
        //        t -> t.errorResponseHandler(new ChickAuthenticationFailureHandler())
        //                .accessTokenResponseHandler(new ChickAuthenticationSuccessHandler()));
        http
                .securityMatcher(authorizationServerConfigurer.getEndpointsMatcher())
                .with(authorizationServerConfigurer, Customizer.withDefaults())
                .authorizeHttpRequests((authorize) ->
                        authorize.anyRequest().authenticated()
                );

        http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
                // 添加扩展的登录方式(老)
                //.tokenEndpoint(tokenEndpoint -> tokenEndpoint
                //        // 添加自定义Converter
                //        .accessTokenRequestConverter(oAuth2PasswordAuthenticationConverter)
                //        // 添加自定义Provider
                //        .authenticationProvider(oAuth2PasswordAuthenticationProvider)
                //)
                // 开启OpenID Connect 1.0（其中oidc为OpenID Connect的缩写）
                .oidc(Customizer.withDefaults());  // Enable OpenID Connect 1.0
        http
                // 将需要认证的请求，重定向到login进行登录认证。
                .exceptionHandling((exceptions) -> exceptions
                        .defaultAuthenticationEntryPointFor(
                                new LoginUrlAuthenticationEntryPoint("/login"),
                                new MediaTypeRequestMatcher(MediaType.TEXT_HTML)
                        )
                )
                // 使用jwt处理接收到的access token
                .oauth2ResourceServer((resourceServer) -> resourceServer
                        .jwt(Customizer.withDefaults()))
                .with(authorizationServerConfigurer, (authorizationServer) -> authorizationServer
                        .tokenEndpoint(tokenEndpoint -> tokenEndpoint
                                .accessTokenRequestConverter(oAuth2PasswordAuthenticationConverter)
                                .authenticationProvider(oAuth2PasswordAuthenticationProvider)
                        )
                );
        return http.build();
    }

    /**
     * Spring Security 过滤链配置（此处是纯Spring Security相关配置）
     */
    @Bean
    @Order(2)
    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http)
            throws Exception {
        http
                .authorizeHttpRequests((authorize) -> authorize
                        // .anyRequest().authenticated()
                        .anyRequest().permitAll()
                )
                .httpBasic(Customizer.withDefaults())
                // Form login handles the redirect to the login page from the
                // authorization server filter chain
                .formLogin(Customizer.withDefaults());
        return http.build();
    }


    /**
     * 自定义Token生成器 暂时先用原来的
     *
     * @return OAuth2TokenGenerator
     */
//    @Bean
//    public OAuth2TokenGenerator<?> tokenGenerator() {
//        UUIDOAuth2TokenGenerator uuidoAuth2TokenGenerator = new UUIDOAuth2TokenGenerator();
//        UUIDOAuth2RefreshTokenGenerator refreshTokenGenerator = new UUIDOAuth2RefreshTokenGenerator();
//        return new DelegatingOAuth2TokenGenerator(uuidoAuth2TokenGenerator, refreshTokenGenerator);
//    }


}